const config = @.merge.advanced({
    "!valueType": "object",
    "!defaultValue": {},
    "testTimeout": {
        "!valueType": "number",
        "!defaultValue": 5000,
    },
    "checkTimeout": {
        "!valueType": "number",
        "!defaultValue": 5000,
    },
    "killThreshold": {
        "!valueType": "number",
        "!defaultValue": -1,
    },
    "killTimeout" : {
        "!valueType": "number",
        "!defaultValue": 60000,
    },
    "testStatement": {
        "!valueType": "string",
        "!defaultValue": "select * from backend_participants limit 0,1",
    }
}, @options("monitor"));

const currentStatus = {
    operate: false
};

const currentRuntime = {
    checkTimer: null,
    testTimer: null,

    timeoutIndex: 0,
    timeoutEvents: []
}




module.exports = function(lab) {
    return {
        "@start": function() {
            if (!currentStatus.operate) {

                function testFunction() {
                    currentRuntime.testTimer = setTimeout(function() {

                        if (config.killThreshold > 0) {
                            currentRuntime.timeoutEvents[currentRuntime.timeoutIndex] = Date.now();

                            if (currentRuntime.timeoutEvents[currentRuntime.timeoutIndex % config.killThreshold] - currentRuntime.timeoutEvents[(currentRuntime.timeoutIndex + config.killThreshold + 1) % config.killThreshold] < config.killTimeout) {

                                @error("we got " + currentRuntime.timeoutEvents.length +  " timeouts within " + config.killTimeout +  " ms");
                                process.exit(-1);

                            }
                        }

                        @warn("backend lab operation timeout");
                        currentRuntime.checkTimer = setTimeout(testFunction, config.checkTimeout);

                    }, config.testTimeout);

                    lab.sqlite.query(config.testStatement).finished(function(error) {
                        clearTimeout(currentRuntime.testTimer);
                        currentRuntime.checkTimer = setTimeout(testFunction, config.checkTimeout);
                    });
                }

                if (config.killThreshold > 0) {

                    currentRuntime.timeoutEvents.length = 0;
                    currentRuntime.timeoutIndex = 0;

                    for (var i = 0; i < config.killThreshold; ++i) {
                        currentRuntime.timeoutEvents.push(0);
                    }

                }
                
                @celebr("start to mornitor backend database operation");

                currentStatus.operate = true;
                currentRuntime.checkTimer = setTimeout(testFunction, config.checkTimeout);
            }
            return currentStatus;
        },
        "@status": function() {
            return @.merge.simple({
                config: config
            }, currentStatus);
        },
        "@stop": function() {
            if (currentStatus.operate) {
                if (currentRuntime.checkTimer) {
                    clearTimeout(currentRuntime.checkTimer);
                }
                if (currentRuntime.testTimer) {
                    clearTimeout(currentRuntime.testTimer);
                }

                currentRuntime.timeoutEvents.length = 0;
                currentRuntime.timeoutIndex = 0;

                currentStatus.operate = false;
            }
            return currentStatus;
        }
    }
}